using System;
using System.Xml;

namespace Slaks.ClusteringInfo
{
	public class ClusteringInfoSerialization
	{
		public static void WriteXml(string path,ClusteringInfo clusteringInfo)
		{
			XmlTextWriter writer = null;
			try
			{
				writer = new XmlTextWriter(path,System.Text.Encoding.UTF8);
				writer.Formatting = System.Xml.Formatting.Indented;
				WriteClusteringInfo(writer,clusteringInfo);
			}catch(Exception)
			{
				throw;
			}
			finally
			{
				if (writer != null) writer.Close();
			}
		}

		public static ClusteringInfo ReadXml(string path)
		{
			ClusteringInfo clusteringInfo = null;
			XmlTextReader reader = null;
			try
			{
				reader = new XmlTextReader(path);
				clusteringInfo = ReadClusteringInfo(reader);
			}
			catch(Exception)
			{
				throw;
			}
			finally
			{
				if (reader != null) reader.Close();
			}
			return clusteringInfo;
		}

		#region Read Methods
		private static ClusteringInfo ReadClusteringInfo(XmlTextReader reader)
		{
			ClusteringInfo info = null;
			/*
			    <algorithm>Kmeans</algorithm>
					<total-iterations>0</total-iterations>
					<current-iteration>10</current-iteration>
					<category-number>4</category-number>
					<cluster-number>0</cluster-number>
					<total-size>0</total-size>
					<series-name>FSeries</series-name>
					<series-path />
		  */

			info = new ClusteringInfo();
			while(reader.Read())
			{
				if (reader.NodeType != XmlNodeType.Element) continue;
				if (string.Equals(reader.Name,Grammar.ClusteringInfo.AlgorithmElement))
					info.Algorithm = reader.ReadString();
				else if (string.Equals(reader.Name, Grammar.ClusteringInfo.TotalIterationsElement))
					info.TotalIterations = int.Parse(reader.ReadString());
				else if (string.Equals(reader.Name, Grammar.ClusteringInfo.CurrentIterationElement))
					info.CurrentIteration = int.Parse(reader.ReadString());
				else if (string.Equals(reader.Name, Grammar.ClusteringInfo.CategoryNumberElement))
					info.CategoryNumber = int.Parse(reader.ReadString());
				else if (string.Equals(reader.Name, Grammar.ClusteringInfo.ClusterNumberElement))
					info.ClusterNumber = int.Parse(reader.ReadString());
				else if (string.Equals(reader.Name, Grammar.ClusteringInfo.TotalSizeElement))
					info.TotalSize = int.Parse(reader.ReadString());
				else if (string.Equals(reader.Name, Grammar.ClusteringInfo.SeriesNameElement))
					info.SeriesName = reader.ReadString();
				else if (string.Equals(reader.Name, Grammar.ClusteringInfo.SeriesPathElement))
				{
					info.SeriesPath = reader.ReadString();
					ReadClusterInfo(reader,info);
				}
				else if (string.Equals(reader.Name, Grammar.Cluster.ClusterElement))
					ReadClusterInfo(reader,info);
			}
			return info;
		}
		private static void ReadClusterInfo(XmlTextReader reader,ClusteringInfo clusteringInfo)
		{
			Cluster cluster = null;
			while(reader.Read())
			{
				if (reader.NodeType == XmlNodeType.Element) 
				{
					if (string.Equals(reader.Name, Grammar.Cluster.ClusterElement)) cluster = new Cluster();
					else if (string.Equals(reader.Name, Grammar.Cluster.SizeElement)) {}
					else if (string.Equals(reader.Name, Grammar.Centroid.CentroidElement)) ReadCentroidInfo(reader,cluster);
					else if (string.Equals(reader.Name, Grammar.DocumentInfo.DocumentInfoElement)) ReadDocumentInfo(reader,cluster);
				}
				else if (reader.NodeType == XmlNodeType.EndElement)
				{
				  if (string.Equals(reader.Name, Grammar.Cluster.ClusterElement))	clusteringInfo.GetClusters().Add(cluster);
					if (string.Equals(reader.Name, Grammar.ClusteringInfo.ClusteringInfoElement)) break;
				}
			}
		}

		private static void ReadCentroidInfo(XmlTextReader reader,Cluster cluster)
		{
			DocumentInfo centroid = new DocumentInfo();
			while(reader.Read())
			{

				if (reader.NodeType == XmlNodeType.Element) 
				{
					if (string.Equals(reader.Name, Grammar.Centroid.NameElement))
						centroid.DocumentName = reader.ReadString();
					else if (string.Equals(reader.Name, Grammar.Centroid.CategoryElement))
						centroid.CategoryName = reader.ReadString();
				}
				else if (reader.NodeType == XmlNodeType.EndElement)
				{
					if (string.Equals(reader.Name, Grammar.Centroid.CentroidElement))
					{
						cluster.Centroid = centroid;
						break;
					}
				}
			}
		}
		private static void ReadDocumentInfo(XmlTextReader reader,Cluster cluster)
		{
			DocumentInfo info = new DocumentInfo();
			while(reader.Read())
			{
				if (reader.NodeType == XmlNodeType.Element) 
				{
					if (string.Equals(reader.Name, Grammar.DocumentInfo.NameElement))
						info.DocumentName = reader.ReadString();
					else if (string.Equals(reader.Name, Grammar.DocumentInfo.CategoryElement))
						info.CategoryName = reader.ReadString();
					else if (string.Equals(reader.Name, Grammar.DocumentInfo.DistanceToCentroid))
						info.DistanceToCentroid = double.Parse(reader.ReadString());
				}
				else if (reader.NodeType == XmlNodeType.EndElement)
				{
					if (string.Equals(reader.Name, Grammar.DocumentInfo.DocumentInfoElement))
					{
						cluster.GetDocuments().Add(info);
						break;
					}
				}
			}
		}
		#endregion

		#region Write Methods
		private static void WriteClusteringInfo(XmlTextWriter writer, ClusteringInfo clusteringInfo)
		{
			writer.WriteStartDocument();
			 writer.WriteStartElement(Grammar.ClusteringInfo.ClusteringInfoElement);
			  writer.WriteElementString(Grammar.ClusteringInfo.AlgorithmElement,clusteringInfo.Algorithm);
			  writer.WriteElementString(Grammar.ClusteringInfo.TotalIterationsElement,clusteringInfo.TotalIterations.ToString());
			  writer.WriteElementString(Grammar.ClusteringInfo.CurrentIterationElement,clusteringInfo.CurrentIteration.ToString());
			  writer.WriteElementString(Grammar.ClusteringInfo.CategoryNumberElement,clusteringInfo.CategoryNumber.ToString());
			  writer.WriteElementString(Grammar.ClusteringInfo.ClusterNumberElement,clusteringInfo.ClusterNumber.ToString());
			  writer.WriteElementString(Grammar.ClusteringInfo.TotalSizeElement,clusteringInfo.TotalSize.ToString());
			  writer.WriteElementString(Grammar.ClusteringInfo.SeriesNameElement,clusteringInfo.SeriesName);
			  writer.WriteElementString(Grammar.ClusteringInfo.SeriesPathElement,clusteringInfo.SeriesPath);
			  
			  foreach(Cluster cluster in clusteringInfo.GetClusters())
			  {
			  	WriteClusterInfo(writer,cluster);
			  }
			 writer.WriteEndElement();
			writer.WriteEndDocument();
		}
		private static void WriteClusterInfo(XmlTextWriter writer, Cluster cluster)
		{
			writer.WriteStartElement(Grammar.Cluster.ClusterElement);
			 writer.WriteElementString(Grammar.Cluster.SizeElement,cluster.GetSize().ToString());
			 WriteCentroidInfo(writer,cluster.Centroid);
			 foreach (DocumentInfo document in cluster.GetDocuments())
			 {
			 	 WriteDocumentInfo(writer,document);
			 }
			writer.WriteEndElement();
		}

		private static void WriteCentroidInfo(XmlTextWriter writer, DocumentInfo centroid)
		{
			writer.WriteStartElement(Grammar.Centroid.CentroidElement);
			 writer.WriteElementString(Grammar.Centroid.NameElement,centroid.DocumentName);
			 writer.WriteElementString(Grammar.Centroid.CategoryElement,centroid.CategoryName);
      writer.WriteEndElement();
		}
		private static void WriteDocumentInfo(XmlTextWriter writer,DocumentInfo documentInfo)
		{
			writer.WriteStartElement(Grammar.DocumentInfo.DocumentInfoElement);
			 writer.WriteElementString(Grammar.DocumentInfo.NameElement,documentInfo.DocumentName);
			 writer.WriteElementString(Grammar.DocumentInfo.CategoryElement,documentInfo.CategoryName);
			 writer.WriteElementString(Grammar.DocumentInfo.DistanceToCentroid,documentInfo.DistanceToCentroid.ToString());
			writer.WriteEndElement();
		}
		#endregion
	}
}
